package org.cybzacg.encryption.utils;

import org.cybzacg.encryption.model.EncryptionResult;
import org.cybzacg.encryption.enums.EncryptionAlgorithm;
import org.cybzacg.encryption.enums.EncryptionType;

import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;
import java.util.Map;
import java.util.HashMap;

/**
 * 序列化工具类
 * 提供加密对象的序列化和反序列化功能
 * 
 * @author encryption team
 * @version 1.0
 */
public class SerializationUtils {
    
    private static final String DEFAULT_CHARSET = StandardCharsets.UTF_8.name();
    private static final int DEFAULT_BUFFER_SIZE = 8192;
    
    /**
     * 序列化对象为加密的字节数组
     * 
     * @param obj 要序列化的对象
     * @param key 加密密钥
     * @param algorithm 加密算法
     * @return 加密的字节数组
     * @throws SerializationException 序列化异常
     */
    public static byte[] serializeToEncryptedBytes(Serializable obj, SecretKey key, EncryptionAlgorithm algorithm) 
            throws SerializationException {
        if (obj == null) {
            throw new SerializationException("Object to serialize cannot be null");
        }
        
        if (key == null) {
            throw new SerializationException("Encryption key cannot be null");
        }
        
        try {
            // 先序列化为字节数组
            byte[] serializedData = serializeToBytes(obj);
            
            // 再加密
            return encryptBytes(serializedData, key, algorithm);
        } catch (Exception e) {
            throw new SerializationException("Failed to serialize and encrypt object: " + e.getMessage(), e);
        }
    }
    
    /**
     * 从加密的字节数组反序列化对象
     * 
     * @param encryptedData 加密的字节数组
     * @param key 解密密钥
     * @param algorithm 加密算法
     * @return 反序列化的对象
     * @throws SerializationException 反序列化异常
     */
    public static <T extends Serializable> T deserializeFromEncryptedBytes(
            byte[] encryptedData, SecretKey key, EncryptionAlgorithm algorithm, Class<T> clazz) 
            throws SerializationException {
        if (encryptedData == null) {
            throw new SerializationException("Encrypted data cannot be null");
        }
        
        if (key == null) {
            throw new SerializationException("Decryption key cannot be null");
        }
        
        try {
            // 先解密
            byte[] serializedData = decryptBytes(encryptedData, key, algorithm);
            
            // 再反序列化
            return deserializeFromBytes(serializedData, clazz);
        } catch (Exception e) {
            throw new SerializationException("Failed to decrypt and deserialize object: " + e.getMessage(), e);
        }
    }
    
    /**
     * 序列化对象为字节数组
     * 
     * @param obj 要序列化的对象
     * @return 序列化的字节数组
     * @throws SerializationException 序列化异常
     */
    public static byte[] serializeToBytes(Serializable obj) throws SerializationException {
        if (obj == null) {
            throw new SerializationException("Object to serialize cannot be null");
        }
        
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            
            oos.writeObject(obj);
            oos.flush();
            return baos.toByteArray();
        } catch (Exception e) {
            throw new SerializationException("Failed to serialize object: " + e.getMessage(), e);
        }
    }
    
    /**
     * 从字节数组反序列化对象
     * 
     * @param data 序列化的字节数组
     * @param clazz 目标类型
     * @return 反序列化的对象
     * @throws SerializationException 反序列化异常
     */
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T deserializeFromBytes(byte[] data, Class<T> clazz) 
            throws SerializationException {
        if (data == null) {
            throw new SerializationException("Data to deserialize cannot be null");
        }
        
        try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
             ObjectInputStream ois = new ObjectInputStream(bais)) {
            
            Object obj = ois.readObject();
            if (!clazz.isInstance(obj)) {
                throw new SerializationException(
                    "Deserialized object is not of type " + clazz.getName());
            }
            return (T) obj;
        } catch (Exception e) {
            throw new SerializationException("Failed to deserialize object: " + e.getMessage(), e);
        }
    }
    
    /**
     * 序列化对象为Base64字符串
     * 
     * @param obj 要序列化的对象
     * @return Base64编码的字符串
     * @throws SerializationException 序列化异常
     */
    public static String serializeToBase64(Serializable obj) throws SerializationException {
        byte[] data = serializeToBytes(obj);
        return Base64.getEncoder().encodeToString(data);
    }
    
    /**
     * 从Base64字符串反序列化对象
     * 
     * @param base64String Base64编码的字符串
     * @param clazz 目标类型
     * @return 反序列化的对象
     * @throws SerializationException 反序列化异常
     */
    public static <T extends Serializable> T deserializeFromBase64(String base64String, Class<T> clazz) 
            throws SerializationException {
        if (base64String == null) {
            throw new SerializationException("Base64 string cannot be null");
        }
        
        try {
            byte[] data = Base64.getDecoder().decode(base64String);
            return deserializeFromBytes(data, clazz);
        } catch (IllegalArgumentException e) {
            throw new SerializationException("Invalid Base64 string: " + e.getMessage(), e);
        }
    }
    
    /**
     * 序列化对象为加密的JSON字符串
     * 
     * @param obj 要序列化的对象
     * @param key 加密密钥
     * @param algorithm 加密算法
     * @return 加密的JSON字符串
     * @throws SerializationException 序列化异常
     */
    public static String serializeToEncryptedJson(Serializable obj, SecretKey key, EncryptionAlgorithm algorithm) 
            throws SerializationException {
        byte[] encryptedData = serializeToEncryptedBytes(obj, key, algorithm);
        return Base64.getEncoder().encodeToString(encryptedData);
    }
    
    /**
     * 从加密的JSON字符串反序列化对象
     * 
     * @param encryptedJson 加密的JSON字符串
     * @param key 解密密钥
     * @param algorithm 加密算法
     * @param clazz 目标类型
     * @return 反序列化的对象
     * @throws SerializationException 反序列化异常
     */
    public static <T extends Serializable> T deserializeFromEncryptedJson(
            String encryptedJson, SecretKey key, EncryptionAlgorithm algorithm, Class<T> clazz) 
            throws SerializationException {
        if (encryptedJson == null) {
            throw new SerializationException("Encrypted JSON cannot be null");
        }
        
        try {
            byte[] encryptedData = Base64.getDecoder().decode(encryptedJson);
            return deserializeFromEncryptedBytes(encryptedData, key, algorithm, clazz);
        } catch (IllegalArgumentException e) {
            throw new SerializationException("Invalid Base64 string: " + e.getMessage(), e);
        }
    }
    
    /**
     * 序列化对象到文件
     * 
     * @param obj 要序列化的对象
     * @param file 目标文件
     * @throws SerializationException 序列化异常
     */
    public static void serializeToFile(Serializable obj, File file) throws SerializationException {
        if (obj == null) {
            throw new SerializationException("Object to serialize cannot be null");
        }
        
        if (file == null) {
            throw new SerializationException("Target file cannot be null");
        }
        
        try (FileOutputStream fos = new FileOutputStream(file);
             ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            
            oos.writeObject(obj);
            oos.flush();
        } catch (Exception e) {
            throw new SerializationException("Failed to serialize object to file: " + e.getMessage(), e);
        }
    }
    
    /**
     * 从文件反序列化对象
     * 
     * @param file 源文件
     * @param clazz 目标类型
     * @return 反序列化的对象
     * @throws SerializationException 反序列化异常
     */
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T deserializeFromFile(File file, Class<T> clazz) 
            throws SerializationException {
        if (file == null) {
            throw new SerializationException("Source file cannot be null");
        }
        
        if (!file.exists()) {
            throw new SerializationException("File does not exist: " + file.getPath());
        }
        
        try (FileInputStream fis = new FileInputStream(file);
             ObjectInputStream ois = new ObjectInputStream(fis)) {
            
            Object obj = ois.readObject();
            if (!clazz.isInstance(obj)) {
                throw new SerializationException(
                    "Deserialized object is not of type " + clazz.getName());
            }
            return (T) obj;
        } catch (Exception e) {
            throw new SerializationException("Failed to deserialize object from file: " + e.getMessage(), e);
        }
    }
    
    /**
     * 序列化加密对象到文件
     * 
     * @param obj 要序列化的对象
     * @param file 目标文件
     * @param key 加密密钥
     * @param algorithm 加密算法
     * @throws SerializationException 序列化异常
     */
    public static void serializeToEncryptedFile(Serializable obj, File file, SecretKey key, EncryptionAlgorithm algorithm) 
            throws SerializationException {
        byte[] encryptedData = serializeToEncryptedBytes(obj, key, algorithm);
        
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(encryptedData);
            fos.flush();
        } catch (Exception e) {
            throw new SerializationException("Failed to write encrypted data to file: " + e.getMessage(), e);
        }
    }
    
    /**
     * 从加密文件反序列化对象
     * 
     * @param file 加密的源文件
     * @param key 解密密钥
     * @param algorithm 加密算法
     * @param clazz 目标类型
     * @return 反序列化的对象
     * @throws SerializationException 反序列化异常
     */
    public static <T extends Serializable> T deserializeFromEncryptedFile(
            File file, SecretKey key, EncryptionAlgorithm algorithm, Class<T> clazz) 
            throws SerializationException {
        if (file == null) {
            throw new SerializationException("Encrypted file cannot be null");
        }
        
        if (!file.exists()) {
            throw new SerializationException("File does not exist: " + file.getPath());
        }
        
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] encryptedData = new byte[(int) file.length()];
            fis.read(encryptedData);
            
            return deserializeFromEncryptedBytes(encryptedData, key, algorithm, clazz);
        } catch (Exception e) {
            throw new SerializationException("Failed to read and decrypt file: " + e.getMessage(), e);
        }
    }
    
    /**
     * 创建对象序列化包装器
     * 
     * @param obj 要包装的对象
     * @return 序列化包装器
     */
    public static SerializationWrapper wrap(Serializable obj) {
        return new SerializationWrapper(obj);
    }
    
    /**
     * 对象序列化包装器
     */
    public static class SerializationWrapper implements Serializable {
        private static final long serialVersionUID = 1L;
        
        private final Serializable wrappedObject;
        private final Map<String, Object> metadata;
        private final long timestamp;
        
        public SerializationWrapper(Serializable wrappedObject) {
            this.wrappedObject = wrappedObject;
            this.metadata = new HashMap<>();
            this.timestamp = System.currentTimeMillis();
        }
        
        public Serializable getWrappedObject() {
            return wrappedObject;
        }
        
        public Map<String, Object> getMetadata() {
            return new HashMap<>(metadata);
        }
        
        public long getTimestamp() {
            return timestamp;
        }
        
        public void addMetadata(String key, Object value) {
            metadata.put(key, value);
        }
        
        public void addMetadata(Map<String, Object> metadata) {
            this.metadata.putAll(metadata);
        }
    }
    
    /**
     * 序列化版本控制包装器
     */
    public static class VersionedWrapper implements Serializable {
        private static final long serialVersionUID = 1L;
        
        private final Serializable wrappedObject;
        private final String version;
        private final String compatibilityVersion;
        
        public VersionedWrapper(Serializable wrappedObject, String version) {
            this.wrappedObject = wrappedObject;
            this.version = version;
            this.compatibilityVersion = version;
        }
        
        public VersionedWrapper(Serializable wrappedObject, String version, String compatibilityVersion) {
            this.wrappedObject = wrappedObject;
            this.version = version;
            this.compatibilityVersion = compatibilityVersion;
        }
        
        public Serializable getWrappedObject() {
            return wrappedObject;
        }
        
        public String getVersion() {
            return version;
        }
        
        public String getCompatibilityVersion() {
            return compatibilityVersion;
        }
        
        public boolean isCompatible(String targetVersion) {
            // 简单的版本兼容性检查
            return compatibilityVersion.equals(targetVersion) || 
                   isVersionCompatible(compatibilityVersion, targetVersion);
        }
        
        private boolean isVersionCompatible(String current, String target) {
            // 实现更复杂的版本兼容性逻辑
            return current.equals(target);
        }
    }
    
    /**
     * 加密字节数组
     */
    private static byte[] encryptBytes(byte[] data, SecretKey key, EncryptionAlgorithm algorithm) 
            throws GeneralSecurityException {
        switch (algorithm) {
            case AES:
                return EncryptionUtils.encryptAES(data, key, KeyGeneratorUtils.generateIV(16)).getData();
            case DES:
                return EncryptionUtils.encryptDES(data, key, KeyGeneratorUtils.generateIV(8)).getData();
            case TRIPLE_DES:
                return EncryptionUtils.encryptTripleDES(data, key, KeyGeneratorUtils.generateIV(8)).getData();
            case BLOWFISH:
                return EncryptionUtils.encryptBlowfish(data, key, KeyGeneratorUtils.generateIV(8)).getData();
            default:
                throw new UnsupportedOperationException("Unsupported algorithm for encryption: " + algorithm);
        }
    }
    
    /**
     * 解密字节数组
     */
    private static byte[] decryptBytes(byte[] encryptedData, SecretKey key, EncryptionAlgorithm algorithm) 
            throws GeneralSecurityException {
        switch (algorithm) {
            case AES:
                return EncryptionUtils.decryptAES(encryptedData, key, KeyGeneratorUtils.generateIV(16));
            case DES:
                return EncryptionUtils.decryptDES(encryptedData, key, KeyGeneratorUtils.generateIV(8));
            case TRIPLE_DES:
                return EncryptionUtils.decryptTripleDES(encryptedData, key, KeyGeneratorUtils.generateIV(8));
            case BLOWFISH:
                return EncryptionUtils.decryptBlowfish(encryptedData, key, KeyGeneratorUtils.generateIV(8));
            default:
                throw new UnsupportedOperationException("Unsupported algorithm for decryption: " + algorithm);
        }
    }
    
    /**
     * 验证对象是否可序列化
     * 
     * @param obj 要验证的对象
     * @return 验证结果
     */
    public static boolean isSerializable(Object obj) {
        if (obj == null) {
            return false;
        }
        
        // 检查是否实现了Serializable接口
        if (!(obj instanceof Serializable)) {
            return false;
        }
        
        // 检查是否为不可变对象（基本类型、String等）
        if (isImmutable(obj)) {
            return true;
        }
        
        // 对于可变对象，检查字段是否都是可序列化的
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.close();
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 检查对象是否为不可变
     */
    private static boolean isImmutable(Object obj) {
        return obj instanceof String ||
               obj instanceof Number ||
               obj instanceof Boolean ||
               obj instanceof Character ||
               obj instanceof Byte ||
               obj instanceof Short ||
               obj instanceof Integer ||
               obj instanceof Long ||
               obj instanceof Float ||
               obj instanceof Double;
    }
    
    /**
     * 创建深拷贝
     * 
     * @param obj 要拷贝的对象
     * @param clazz 目标类型
     * @return 深拷贝的对象
     * @throws SerializationException 序列化异常
     */
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T deepCopy(T obj, Class<T> clazz) throws SerializationException {
        if (obj == null) {
            return null;
        }
        
        byte[] data = serializeToBytes(obj);
        return deserializeFromBytes(data, clazz);
    }
    
    /**
     * 获取序列化大小
     * 
     * @param obj 要测量的对象
     * @return 序列化后的字节数
     * @throws SerializationException 序列化异常
     */
    public static int getSerializedSize(Serializable obj) throws SerializationException {
        if (obj == null) {
            return 0;
        }
        
        return serializeToBytes(obj).length;
    }
    
    /**
     * 批量序列化
     * 
     * @param objects 要序列化的对象列表
     * @return 序列化结果映射
     */
    public static Map<String, byte[]> batchSerialize(Map<String, Serializable> objects) {
        Map<String, byte[]> results = new HashMap<>();
        
        for (Map.Entry<String, Serializable> entry : objects.entrySet()) {
            try {
                byte[] data = serializeToBytes(entry.getValue());
                results.put(entry.getKey(), data);
            } catch (SerializationException e) {
                // 记录失败的序列化，但继续处理其他对象
                results.put(entry.getKey(), null);
            }
        }
        
        return results;
    }
    
    /**
     * 批量反序列化
     * 
     * @param serializedData 序列化数据映射
     * @param targetTypes 目标类型映射
     * @return 反序列化结果映射
     */
    public static Map<String, Object> batchDeserialize(
            Map<String, byte[]> serializedData, 
            Map<String, Class<?>> targetTypes) {
        
        Map<String, Object> results = new HashMap<>();
        
        for (Map.Entry<String, byte[]> entry : serializedData.entrySet()) {
            String key = entry.getKey();
            byte[] data = entry.getValue();
            Class<?> targetType = targetTypes.get(key);
            
            if (data != null && targetType != null) {
                try {
                    Object obj = deserializeFromBytes(data, (Class<? extends Serializable>) targetType);
                    results.put(key, obj);
                } catch (SerializationException e) {
                    // 记录失败的反序列化，但继续处理其他对象
                    results.put(key, null);
                }
            }
        }
        
        return results;
    }
}

/**
 * 序列化异常类
 */
class SerializationException extends Exception {
    
    public SerializationException(String message) {
        super(message);
    }
    
    public SerializationException(String message, Throwable cause) {
        super(message, cause);
    }
}
